﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cool.Application.System.MenuService.Dtos;
using Cool.Core.ComDto;
using Cool.Core.Entities.System;
using Cool.Core.Enums;
using Cool.Core.Managers;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Cool.Application.System.MenuService
{
    [Authorize]
    [ApiDescriptionSettings("System")]
    [Route("api/system/[controller]")]
    public class MenuService : IMenuService, ITransient, IDynamicApiController
    { 
        /// <summary>
        /// 菜单仓储
        /// </summary>
        private readonly IRepository<SysMenu> _menuRepository;

        /// <summary>
        /// 用户管理类
        /// </summary>
        private readonly IUserManager _userManager;

        /// <summary>
        /// 角色菜单配置仓储
        /// </summary>
        private readonly IRepository<SysRoleMenu> _roleMenuRepository;

        /// <summary>
        /// 用户
        /// </summary>
        private readonly IRepository<SysUserRole> _userRoleRepository;

        private readonly Func<List<MenuTreeTableReturnDto>, int, List<MenuTreeTableReturnDto>> authMenufunc = null;

        private readonly Func<List<SysMenu>, int, List<TreeOutData>> roleMenuFunc = null;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="menuRepository"></param>
        /// <param name="userManager"></param>
        /// <param name="roleMenuRepository"></param>
        /// <param name="userRoleRepository"></param>
        public MenuService(IRepository<SysMenu> menuRepository, IUserManager userManager
            , IRepository<SysRoleMenu> roleMenuRepository,
            IRepository<SysUserRole> userRoleRepository)
        {
            _menuRepository = menuRepository;
            _userManager = userManager;
            _roleMenuRepository = roleMenuRepository;
            _userRoleRepository = userRoleRepository;

            authMenufunc = delegate (List<MenuTreeTableReturnDto> allList, int parentId)
            {
                var childrenList = allList.Where(p => p.ParentId == parentId).OrderBy(p => p.OrderNum).ToList();
                foreach (var menuList in childrenList)
                {
                    menuList.children = authMenufunc(allList, menuList.Id);
                }
                return childrenList;
            };
            roleMenuFunc = delegate (List<SysMenu> allList, int parentId)
            {
                var childrenList = allList.Where(p => p.ParentId == parentId).OrderBy(p => p.OrderNum).ToList();
                var treeDataOuts = new List<TreeOutData>();
                foreach (var menuList in childrenList)
                {
                    var menuOutData = new TreeOutData
                    {
                        Id=menuList.Id,
                        Label=menuList.MenuName
                    };
                    menuOutData.Children = roleMenuFunc(allList, menuList.Id);
                    treeDataOuts.Add(menuOutData);
                }
                return treeDataOuts;
            };
        }

        /// <summary>
        /// 获取vab菜单
        /// </summary>
        public List<MenuOutDto> GetMenus()
        {
            var currentUserId = _userManager.UserId;

            var menus = (from userRole in _userRoleRepository.AsQueryable()
                join roleMenu in _roleMenuRepository.AsQueryable() on userRole.RoleId equals roleMenu.RoleId
                join menu in _menuRepository.AsQueryable() on roleMenu.MenuId equals menu.Id into result
                from menu in result.DefaultIfEmpty()
                where userRole.UserId==currentUserId && menu.MenuType=='M' || menu.MenuType=='C'
                select menu).Distinct();
            var allList = menus.ToList();

            var menuOutDtos = new List<MenuOutDto>();
            foreach (var root in allList.Where(p => p.ParentId == -1).OrderBy(p=>p.OrderNum))
            {
                var menu = new MenuOutDto();
                menu.component = root.Component;
                if (!string.IsNullOrEmpty(root.MenuName))
                {
                    menu.meta = new MenuMeta() { icon = root.Icon, noCache=root.IsCache=='1', title = root.MenuName, permissions = new List<string>() { "admin" } };
                }
                menu.name = root.Path;
                menu.path = root.Path;

                menu.children = getChildrenMenu(allList, root.Id);
                menuOutDtos.Add(menu);
            }

            return menuOutDtos;
        }

        public async Task<List<TreeOutData>> GetTreeSelect()
        {
            var allList = await _menuRepository.AsQueryable().ToListAsync();
            return roleMenuFunc(allList, -1);
        }

        public async Task<dynamic> GetRoleMenuTreeSelect([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的角色 Id")] int roleId)
        {
            var menus = await GetTreeSelect();
            var roleList = await _roleMenuRepository.Where(p => p.RoleId == roleId).ToListAsync();

            return new
            {
                menus,
                checkedKeys= roleList.Select(p=>p.MenuId).ToArray()
            };
        }

        private List<MenuOutDto> getChildrenMenu(List<SysMenu> allList, int parentId)
        {
            var childrenDtos = new List<MenuOutDto>();
            foreach (var children in allList.Where(p => p.ParentId == parentId).OrderBy(p => p.OrderNum))
            {
                MenuOutDto menu = new MenuOutDto();
                menu.component = children.Component;
                if (!string.IsNullOrEmpty(children.MenuName))
                {
                    menu.meta = new MenuMeta() { icon = children.Icon, noCache = children.IsCache == '1', title = children.MenuName };
                }
                menu.name = children.Path;
                menu.path = children.Path;

                menu.children = getChildrenMenu(allList, children.Id);
                childrenDtos.Add(menu);
            }

            return childrenDtos;
        }

        #region 配置页面接口
        /// <summary>
        /// 获取菜单树列表
        /// </summary>
        /// <param name="menuTreeTableSearchDto">查询参数</param>
        /// <returns></returns>
        [ HttpGet, ApiDescriptionSettings(Name = "treelist")]
        public async Task<List<MenuTreeTableReturnDto>> GetListAsync([FromQuery] MenuTreeTableSearchDto menuTreeTableSearchDto)
        {
            var hasMenuName = !string.IsNullOrEmpty(menuTreeTableSearchDto.MenuName?.Trim());
            var hasStatus = menuTreeTableSearchDto.Status!=null;

            var menuTreeList= await _menuRepository.Where(
                (hasMenuName, u => EF.Functions.Like(u.MenuName, $"%{menuTreeTableSearchDto.MenuName.Trim()}%")),
                (hasStatus, u => u.Status == menuTreeTableSearchDto.Status)
            ).ToListAsync();

            var adaptTreeList = menuTreeList.Adapt<List<MenuTreeTableReturnDto>>();

            return authMenufunc(adaptTreeList, -1);
        }

        /// <summary>
        /// 根据菜单Id获取菜单信息
        /// </summary>
        /// <param name="menuId"></param>
        /// <returns></returns>
        public async Task<SysMenu> GetAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的菜单 Id")] int menuId)
        {
            return await _menuRepository.FindAsync(menuId);
        }

        /// <summary>
        /// 新增菜单
        /// </summary>
        /// <param name="menu"></param>
        /// <returns></returns>
        public async Task<SysMenu> AddAsync([Required] SysMenu menu)
        {
            var entryEntity= await _menuRepository.InsertAsync(menu);
            return entryEntity.Entity;
        }

        /// <summary>
        /// 修改菜单
        /// </summary>
        /// <param name="menu"></param>
        /// <returns></returns>
        public async Task UpdateAsync([Required] SysMenu menu)
        {
            await _menuRepository.UpdateExcludeAsync(menu, new[] { nameof(SysMenu.IsDeleted), nameof(SysMenu.CreatedTime) }, ignoreNullValues: true);
        }

        /// <summary>
        /// 删除菜单
        /// </summary>
        /// <param name="menuId"></param>
        /// <returns></returns>
        public async Task DeleteAsync([Required, Range(1, int.MaxValue, ErrorMessage = "请输入有效的菜单 Id")]int menuId)
        {
            var deleteMenu = await _menuRepository.FindAsync(menuId);
            _ = deleteMenu ?? throw Oops.Oh(SystemErrorCodes.u1002);

            // 软/假删除
            deleteMenu.IsDeleted = true;
        }

        #endregion
    }
}
